package com.yuan.pay_mall.service.impl;

import com.google.gson.Gson;
import com.yuan.pay_mall.dao.ProductMapper;
import com.yuan.pay_mall.enums.ProductStatusEnum;
import com.yuan.pay_mall.form.CartAddForm;
import com.yuan.pay_mall.form.CartUpdateForm;
import com.yuan.pay_mall.pojo.Cart;
import com.yuan.pay_mall.pojo.Product;
import com.yuan.pay_mall.service.ICartService;
import com.yuan.pay_mall.vo.CartProductVo;
import com.yuan.pay_mall.vo.CartVo;
import com.yuan.pay_mall.vo.ResponseVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.yuan.pay_mall.enums.ResponseEnum.*;

@Service
public class CartServiceImpl implements ICartService {
    private final static String CART_REDIS_KEY_TEMPLATE="cart_%d";//一个id就是一个顾客

    private Gson gson=new Gson();
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public ResponseVo<CartVo> add(Integer uid,CartAddForm form) {
        Integer quantity = 1;

        Product product = productMapper.selectByPrimaryKey(form.getProductId());
        //判断商品是否存在
        if (product == null) {
            return ResponseVo.error(PRODUCT_NOT_EXIST);
        }
        //商品是否正常在售卖
        if (!product.getStatus().equals(ProductStatusEnum.ON_SALE.getCode())) {
            return ResponseVo.error(PRODUCT_OFF_SALE_OR_DELETE);
        }
        //商品库存是否充足
        if (product.getStock() <=0) {
            return ResponseVo.error(PRODUCT_STOCK_ERROR);
        }
        //写入到redis
        /**
         * springBoot往redis写入数据的地方
         * 1.引依赖2个，不然redis注入不成功
         * 2.配置yum信息
         */
        //key:cart_1   转变成hash类型
       /* redisTemplate.opsForValue().set(String.format(CART_REDIS_KEY_TEMPLATE,uid),//key
                gson.toJson(new Cart(product.getId(), quantity,form.getSelected())));*///value是个对象转String

        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);

        Cart cart ;
        //通过get(H key, Object hashKey)方法获取map键的值
        String value = opsForHash.get(redisKey, String.valueOf(product.getId()));
        if(StringUtils.isEmpty(value)){
            //没有该商品
            cart = new Cart(product.getId(),quantity,form.getSelected());
        }else{
            //已经有了，数量+1
            cart = gson.fromJson(value,Cart.class);//String,要转向的对象类型
            cart.setQuantity(cart.getQuantity() + quantity);
        }
        opsForHash.put(redisKey,
                String.valueOf(product.getId()),
                gson.toJson(cart));
       /* opsForHash.put(String.format(CART_REDIS_KEY_TEMPLATE,uid),
                String.valueOf(product.getId()),
                gson.toJson(new Cart(product.getId(), quantity,form.getSelected())));*/
        return list(uid);
    }

    @Override  //列出单个商品的所有属性信息
    public ResponseVo<CartVo> list(Integer uid) {
        //从redis中拿数据
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        //通过entries(H key)方法获取变量中的键值对
        Map<String, String> entries = opsForHash.entries(redisKey);
        boolean selectAll = true;
        Integer cartTotalQuantity=0;
        BigDecimal cartTotalPrice=BigDecimal.ZERO;

        CartVo cartVo = new CartVo();
        List<CartProductVo> cartProductVoList = new ArrayList<>();
        //遍历域中的所有键值对（对象中的属性），查询数据库拿到商品的所有属性
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Integer productId = Integer.valueOf(entry.getKey());
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);
            //TODO 需要优化，使用mysql里的in,不要在循环中写查询语句
            //select * from mall_product where entry in(属性...)
            Product product = productMapper.selectByPrimaryKey(productId);
            //商品是否存在，必须先查到才有
            if(product != null){
                CartProductVo cartProductVo = new CartProductVo(productId, cart.getQuantity(),
                        product.getName(),
                        product.getSubtitle(),
                        product.getMainImage(),
                        product.getPrice(),
                        product.getStatus(),
                        product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())),
                        product.getStock(),
                        cart.getProductSelected());
                cartProductVoList.add(cartProductVo);
                //看商品是否被选中
                if(!cart.getProductSelected()){
                    selectAll = false;
                }
                //计算总价（只计算选中的）业务
                if(cart.getProductSelected()){
                    cartTotalPrice =cartTotalPrice .add(cartProductVo.getProductTotalPrice());
                }

            }
            cartTotalQuantity +=cart.getQuantity();
        }
        //是否全选，有一个没选中就不是全选
        cartVo.setSelectedAll(selectAll);
        cartVo.setCartTotalQuantity(cartTotalQuantity);
        cartVo.setCartTotalPrice(cartTotalPrice);
        cartVo.setCartProductVoList(cartProductVoList);

        return ResponseVo.success(cartVo);
    }

    @Override
    public ResponseVo<CartVo> update(Integer uid, Integer productId, CartUpdateForm form) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        //通过get(H key, Object hashKey)方法获取map键的值
        //这里的value是redis中存储的购物车中单个商品的全部属性
        String value = opsForHash.get(redisKey, String.valueOf(productId));
        if(StringUtils.isEmpty(value)){
            //没有该商品 报错
            return ResponseVo.error(CART_PRODUCT_NOT_EXIST);
        }
        //已经有了,修改内容
        //传商品数量
        Cart cart = gson.fromJson(value,Cart.class);//String,要转向的对象类型
        if(form.getQuantity() != null && form.getQuantity() >=0){ //数量不为空
            cart.setQuantity(form.getQuantity());
        }
        //传是否选中
        if(form.getSelected() !=null){
            cart.setProductSelected(form.getSelected());
        }
        opsForHash.put(redisKey, String.valueOf(productId), gson.toJson(cart));
        return list(uid);

    }

    @Override
    public ResponseVo<CartVo> delete(Integer uid, Integer productId) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        //通过get(H key, Object hashKey)方法获取map键的值
        //这里的value是redis中存储的购物车中单个商品的全部属性
        String value = opsForHash.get(redisKey, String.valueOf(productId));
        if(StringUtils.isEmpty(value)){
            //没有该商品 报错
            return ResponseVo.error(CART_PRODUCT_NOT_EXIST);
        }
        opsForHash.delete(redisKey, String.valueOf(productId));
        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> selectAll(Integer uid) {
        //从redis中拿数据
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        for (Cart cart : listForCart(uid)) {
            cart.setProductSelected(true);
            opsForHash.put(redisKey,String.valueOf(cart.getProductId()), gson.toJson(cart));
        }
        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> unSelectAll(Integer uid) {
        //从redis中拿数据
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        for (Cart cart : listForCart(uid)) {
            cart.setProductSelected(false);
            opsForHash.put(redisKey,String.valueOf(cart.getProductId()), gson.toJson(cart));
        }
        return list(uid);
    }

    @Override
    public ResponseVo<Integer> sum(Integer uid) {
        //Stream中reduce（）方法;根据指定的计算模型将Stream中的值计算得到一个最终结果。
        //https://wenku.baidu.com/view/cb9bc4db6237ee06eff9aef8941ea76e58fa4ae0.html?_wkts_=1679577912789&bdQuery=java8+stream%E4%B8%AD%E7%9A%84reduce%E6%96%B9%E6%B3%95
        Integer sum = listForCart(uid).stream().
                map(Cart::getQuantity).//获取里面的数量
                reduce(0,Integer::sum);//从0开始累加
        return ResponseVo.success(sum);
    }

    //遍历redis中的数据信息，根据id拿到顾客购物车中的商品全部信息
    private List<Cart> listForCart(Integer uid){
        //从redis中拿数据
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        List<Cart> cartList = new ArrayList<>();
        //通过entries(H key)方法获取变量中的键值对
        Map<String, String> entries = opsForHash.entries(redisKey);
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            cartList.add(gson.fromJson(entry.getValue(),Cart.class));
        }
        return cartList;
    }
}


